package charts; 

import charts.series.dots.DotFactory;
import charts.series.dots.PointDotBase;
import charts.series.Element;
//import charts.Structs.StyleStruct;

import flash.display.BlendMode;
import flash.display.Graphics;
import flash.display.Sprite;

import string.Utils;

class LineBase<StyleType, ValueType> extends Base<ValueType> {

	// JSON style:
	var style:StyleType;

	var key:String;
	var font_size:Float;
	var values:Array<ValueType>; // TODO - figure out the actual type instead of Dynamic
		
	public function new() {super();}
	
	//
	// called from the LineBase object
	//
	override function get_element( index:Float, value:ValueType ): ValueType {

		//var s:Object = this.merge_us_with_value_object( value );
		//
		// the width of the hollow circle is the same as the width of the line
		//

		var props:Properties;
		if( Std.is( value, Float) )
			props = new Properties( { value:value }, style.__dot_style);
		else
			props = new Properties( value, style.__dot_style);
			
		return DotFactory.make( index, props );
	}
	
	
	// Draw lines...
	public override function resize( sc:ScreenCoordsBase ): Void {
		this.x = this.y = 0;

		this.graphics.clear();
		this.graphics.lineStyle( style.width, style.colour );
		
		if( style.line_style.style != 'solid' )
			this.dash_line(sc);
		else
			this.solid_line(sc);
	
	}
	
	public function solid_line( sc:ScreenCoordsBase ): Void {
		var first:Bool = true;
		var i:Float;
		var spr:Sprite;
		var x:Float;
		var y:Float;
		
		for ( i in 0...this.numChildren) {

			spr = cast( this.getChildAt(i), Sprite);
			
			//
			// filter out the line masks
			//
			if( Std.is( spr, Element) )
			{
				var e:Element = cast( spr, Element);
				
				// tell the Point where it is on the screen
				// we will use this info to place the tooltip
				e.resize( sc );
				if( first )
				{
					this.graphics.moveTo(e.x, e.y);
					x = e.x;
					y = e.y;
					first = false;
				}
				else
					this.graphics.lineTo(e.x, e.y);
			}
		}
		
		if ( style.loop ) {
			// close the line loop (radar charts)
			this.graphics.lineTo(x, y);
		}
	}
	
	// Dashed lines by Arseni
	public function dash_line( sc:ScreenCoordsBase ): Void {
		
		var first:Bool = true;
		
		var prev_x:Int = 0;
		var prev_y:Int = 0;
		var on_len_left:Int = 0;
		var off_len_left:Int = 0;
		var on_len:Int = style.line_style.on; //Stroke Length
		var off_len:Int = style.line_style.off; //Space Length
		var now_on:Bool = true;
		
		for ( i in 0...this.numChildren) {				
			var spr:Sprite = cast( this.getChildAt(i), Sprite);
			//
			// filter out the line masks
			//
			if( !Std.is( spr, Element) )
			{
				continue;
			}
			var e:Element = cast( spr, Element);
			
			// tell the Point where it is on the screen
			// we will use this info to place the tooltip
			e.resize( sc );
			if( first )
			{
				this.graphics.moveTo(e.x, e.y);
				on_len_left = on_len;
				off_len_left = off_len;
				now_on = true;
				first = false;
				prev_x = e.x;
				prev_y = e.y;
				var x_tmp_1:Int = prev_x;
				var x_tmp_2:Float;
				var y_tmp_1:Int = prev_y;
				var y_tmp_2:Float;
			}else {
				var part_len:Int = Math.sqrt((e.x - prev_x) * (e.x - prev_x) + (e.y - prev_y) * (e.y - prev_y) );
				var sinus:Int = ((e.y - prev_y) / part_len); 
				var cosinus:Int = ((e.x - prev_x) / part_len); 
				var part_len_left:Int = part_len;
				var inside_part:Bool = true;
					
				while (inside_part) {
					//Draw Lines And spaces one by one in loop
					if ( now_on ) {
						//Draw line
						//If whole stroke fits
						if (  on_len_left < part_len_left ) {
							//Fits - draw whole stroke
							x_tmp_2 = x_tmp_1 + on_len_left * cosinus;
							y_tmp_2 = y_tmp_1 + on_len_left * sinus;
							x_tmp_1 = x_tmp_2;
							y_tmp_1 = y_tmp_2;
							part_len_left = part_len_left - on_len_left;
							now_on = false;
							off_len_left = off_len;															
						} else {
							//Does not fit - draw part of the stroke
							x_tmp_2 = e.x;
							y_tmp_2 = e.y;
							x_tmp_1 = x_tmp_2;
							y_tmp_1 = y_tmp_2;
							on_len_left = on_len_left - part_len_left;
							inside_part = false;									
						}
						this.graphics.lineTo(x_tmp_2, y_tmp_2);								
					} else {
						//Draw space
						//If whole space fits
						if (  off_len_left < part_len_left ) {
							//Fits - draw whole space
							x_tmp_2 = x_tmp_1 + off_len_left * cosinus;
							y_tmp_2 = y_tmp_1 + off_len_left * sinus;
							x_tmp_1 = x_tmp_2;
							y_tmp_1 = y_tmp_2;
							part_len_left = part_len_left - off_len_left;								
							now_on = true;
							on_len_left = on_len;
						} else {
							//Does not fit - draw part of the space
							x_tmp_2 = e.x;									
							y_tmp_2 = e.y;									
							x_tmp_1 = x_tmp_2;
							y_tmp_1 = y_tmp_2;
							off_len_left = off_len_left - part_len_left;
							inside_part = false;																		
						}
						this.graphics.moveTo(x_tmp_2, y_tmp_2);								
					}
				}
			}
			prev_x = e.x;
			prev_y = e.y;
			
		}
	}
	
	function merge_us_with_value_object( value:ValueType ): StyleType {
		
		var default_style:StyleType = {
			axis			: style.axis
			, colour			: style.colour
			, dot_size		: style.dot_size
			, halo_size		: style.halo_size
			, onclick		: style.onclick
			, tip			: style.tip
		}
		
		if( Std.is( value, Float) )
			default_style.value = value;
		else
			Object_helper.merge_2( value, default_style );
		
		// our parent colour is a number, but
		// we may have our own colour:
		if( Std.is( default_style.colour, String) )
			default_style.colour = Utils.get_colour( default_style.colour );
			
		// Minor hack, replace all #key# with this LINEs key text:
		default_style.tip =  StringTools.replace(default_style.tip,'#key#', style.text);
		
		return default_style;
	}
	
	public override function get_colour(): Float {
		return style.colour;
	}
}
